package java2_chatroom;

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 多线程版本服务器端
 * @author yuisama
 * @date 2018/8/31 20:43
 */
public class MultiThreadServer {
    // 采用concurrentHashMap存储所有连接到服务器的客户端信息
    private static Map<String, Socket> clientMap =
            new ConcurrentHashMap<String, Socket>();
    // 采用内部类具体处理每一个客户端请求

    /**
     * userName:test(注册)
     * G:hello(群聊)
     * P:test-聊天内容(私聊)
     * byebye(用户退出)
     */
    private static class ExecuteRealClient implements Runnable{
        private Socket client;

        public ExecuteRealClient(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            try {
                // 获取客户端输入流，读取用户发来的信息
                Scanner in = new Scanner(client.getInputStream());
                String str = "";
                while (true) {
                    if (in.hasNextLine()) {
                        str = in.nextLine();
                        // 识别windows下换行符,将/r替换为""
                        Pattern pattern = Pattern.compile("\r");
                        Matcher matcher = pattern.matcher(str);
                        matcher.replaceAll("");
                        // 注册流程
                        if (str.startsWith("userName")) {
                            // userName:test
                            String userName = str.split("\\:")[1];
                            userRegister(userName,client);
                            continue;
                        }
                        // 群聊流程
                        if (str.startsWith("G")) {
                            // G:hello
                            String msg = str.split("\\:")[1];
                            groupChat(msg);
                            continue;
                        }
                        // 私聊流程
                        if (str.startsWith("P")) {
                            // P:test-123
                            String userName = str.split("\\:")[1]
                                    .split("\\-")[0];
                            String msg = str.split("\\:")[1]
                                    .split("\\-")[1];
                            privateChat(userName,msg);
                            continue;
                        }
                        // 客户端退出
                        if (str.contains("byebye")) {
                            // 遍历Map，获取userName
                            String userName = "";
                            for (String key : clientMap.keySet()) {
                                if (clientMap.get(key).equals(client)) {
                                    userName = key;
                                }
                            }
                            System.out.println("用户"+userName+"下线了..");
                            clientMap.remove(userName);
                            System.out.println("当前聊天室一共"+clientMap.size()+"人");
                            continue;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 注册方法
        private static void userRegister(String userName,Socket socket) {
            System.out.println("用户"+userName+"上线了!");
            // 将用户保存在map
            clientMap.put(userName,socket);
            System.out.println("当前聊天室中一共有"+clientMap.size()+"人");
            try {
                // 告知客户端注册成功
                PrintStream out = new PrintStream(socket.getOutputStream());
                out.println("用户注册成功!");
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        // 群聊方法
        private static void groupChat(String msg) {
            Set<Map.Entry<String,Socket>> clientSet =
                    clientMap.entrySet();
            for (Map.Entry<String,Socket> entry : clientSet) {
                // 遍历取出每个Socket
                Socket socket = entry.getValue();
                try {
                    // 获取每个Socket的输出流
                    PrintStream out = new PrintStream(socket.getOutputStream());
                    out.println("群聊消息为: "+msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        // 私聊方法
        private static void privateChat(String userName,String msg) {
            // 根据用户名获取指定Socket
            Socket socket = clientMap.get(userName);
            try {
                // 获得指定Socket输出流
                PrintStream out = new PrintStream(socket.getOutputStream());
                out.println("私聊消息: "+msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    public static void main(String[] args) throws Exception{
        // 创建大小为20的线程池
        ExecutorService executorService =
                Executors.newFixedThreadPool(20);
        // 建立基站
        ServerSocket serverSocket = new ServerSocket(6666);
        for (int i = 0 ; i < 20 ; i++) {
            System.out.println("等待客户端连接....");
            Socket client = serverSocket.accept();
            System.out.println("有新的客户端连接，端口号为 "+client.getPort());
            // 每当有用户连接，新建线程处理
            executorService.submit(new ExecuteRealClient(client));
        }
        executorService.shutdown();
        serverSocket.close();
    }
}
